﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using EpcTagLibrary;
using EpcTagLibrary.Pat;
using ALE_Server.EC;
using ALE_Server.ECException;

namespace ALE_Server
{
    public class EventReport
    {
        private IDictionary<TagEvent, EPC> m_FilteredTags = new Dictionary<TagEvent, EPC>();
        private IList<EPC> m_DefaultTagGroup = new List<EPC>();

        private IList<Pattern> m_Groups;
        private IList<Pattern> m_IncludeFilters;
        private IList<Pattern> m_ExcludeFilters;
        private ECReportSpec m_Spec;
        private EventReport m_PreviousReport;

        public EventReport(ECReportSpec spec, EventReport previousReport)
        {
            m_Spec = spec;

            if ((previousReport != null) && !previousReport.m_Spec.Equals(spec))
            {
                throw new EventReportException("Spec Mismatch");
            }

            m_PreviousReport = previousReport;

            if (spec.Filter.ExcludePattern != null)
            {                
                m_ExcludeFilters = new List<Pattern>();

                foreach (ECExcludePattern pattern in spec.Filter.ExcludePattern)
                {
                    m_ExcludeFilters.Add(PatternFactory.NewInstance(pattern.ToString()));
                } 
            }

            if (spec.Filter.IncludePattern != null)
            {
                 m_IncludeFilters = new List<Pattern>();
                foreach(ECIncludePattern pattern in spec.Filter.IncludePattern)
                {
                    m_IncludeFilters.Add(PatternFactory.NewInstance(pattern.ToString()));
                }
            }

            if (spec.Group != null)
            {
                m_Groups = new List<Pattern>();

                foreach (string pattern in spec.Group.PatternList)
                {
                    m_Groups.Add(PatternFactory.NewInstance(pattern));
                }
            }
        }

        public void TagEvent(TagEvent te)
        {
            if (m_ExcludeFilters != null)
            {
                foreach (Pattern pattern in m_ExcludeFilters)
                {
                    if (pattern.Match(te.Tag))
                    {
                        return;
                    }
                }
            }

            if (m_IncludeFilters != null)
            {
                bool Include = false;

                foreach (Pattern pattern in m_IncludeFilters)
                {
                    if (pattern.Match(te.Tag))
                    {
                        Include = true;
                        break;
                    }

                    if (!Include)
                    {
                        return;
                    }
                }
            }

            m_FilteredTags.Add(te,te.Tag);
        }

        public void DoTags(IList<TagEvent> tags)
        {
            foreach (TagEvent tag in tags)
            {
                TagEvent(tag);
            }
        } 
        
        public void Reset()
        {
            m_PreviousReport = null;
        }

        public IDictionary<TagEvent,EPC> GetReportSetTags()
        {
            IDictionary<TagEvent,EPC> Result = new Dictionary<TagEvent,EPC>(m_FilteredTags);

            if ((ECReportSetEnum.CURRENT == m_Spec.ReportSet) || (m_PreviousReport == null) || (m_PreviousReport.m_FilteredTags.Count ==0))
            {
                return Result;
            }
            else if (ECReportSetEnum.ADDITIONS == m_Spec.ReportSet) 
            {
                foreach (TagEvent te in Result.Keys)
                {
                    EPC tag = Result[te];

                    if (m_PreviousReport.m_FilteredTags.Keys.Contains(te))
                    {
                        Result.Remove(te);
                    }
                }
            }
            else 
            {
                Result.Clear();

                foreach (TagEvent te in m_PreviousReport.m_FilteredTags.Keys)
                {
                    if (!m_FilteredTags.Keys.Contains(te))
                    {
                        Result.Add(te,te.Tag);
                    }
                }
            }

            return Result;
        }


        public ECReport GetECReport()
        {
            if (m_Spec.ReportOnlyOnChange && (m_PreviousReport != null))
            {
                if (m_FilteredTags.Count == m_PreviousReport.m_FilteredTags.Count)
                {
                    bool ReturnNull = true;
                    foreach (EPC epc in m_PreviousReport.m_FilteredTags.Values)
                    {
                        if (!m_PreviousReport.m_FilteredTags.Values.Contains(epc))
                        {
                            ReturnNull = false;
                            break;
                        }
                    }

                    if (ReturnNull)
                    {
                        return null;
                    }
                }
            }

            m_FilteredTags = GetReportSetTags();

            if ((m_FilteredTags.Count == 0) && !m_Spec.ReportIfEmpty)
            {
                return null;
            }

            foreach (TagEvent Event in m_FilteredTags.Keys)
            {
                bool Include = false;
                if (m_Groups != null)
                {
                    foreach (Pattern P in m_Groups)
                    {
                        if (P.Group(new EPCWrapper(Event)))
                        {
                            Include = false;
                            break;
                        }
                    }
                }

                if (!Include)
                {
                    m_DefaultTagGroup.Add(new EPCWrapper(Event));
                }
            }

            ECReport Result = new ECReport();
            Result.ReportName = m_Spec.ReportName;

            if (m_Groups != null)
            {
                foreach (Pattern P in m_Groups)
                {
                    IList<GroupField> Leaves = P.Leaves;

                    foreach (GroupField GF in Leaves)
                    {
                        ECReportGroup ECRG = new ECReportGroup();
                        Result.AddGroup(ECRG);

                        if (m_Spec.Output.IsIncludeCount)
                        {
                            ECReportGroupCount ReportGroupCount = new ECReportGroupCount(GF.Epcs.Count);
                            ECRG.GroupCount = ReportGroupCount;
                        }

                        StringBuilder GrpName = new StringBuilder();
                        GrpName.Append(GF.Pattern.IsGrouping ? GF.Value : GF.Pattern.Component);

                        GroupField PRNT = GF;
                        while ((PRNT = PRNT.Parent).Pattern != null)
                        {
                            GrpName.Insert(0, '.');
                            GrpName.Insert(0, PRNT.Pattern.IsGrouping ? PRNT.Value : PRNT.Pattern.Component);
                        }
                        GrpName.Insert(0, ":");
                        GrpName.Insert(0, P.GetScheme());
                        GrpName.Insert(0, "urn:epc:pat:");

                        foreach (EPC Epc in GF.Epcs)
                        {
                            EPCWrapper epc = Epc as EPCWrapper;
                            ECReportGroupListMember Member = new ECReportGroupListMember();
                            ECRG.AddMember(Member);
                            Member.EpcTag = epc;

                            if (m_Spec.Output.IsIncldeEPC)
                            {
                                Member.EpcSet = true;
                            }
                            if (m_Spec.Output.IsIncludeTag)
                            {
                                Member.TagSet = true;
                            }
                            if (m_Spec.Output.IsIncludeRawDecimal)
                            {
                                Member.RawDecSet = true;
                            }
                            if (m_Spec.Output.IsIncludeRawHex)
                            {
                                Member.RawHexSet = true;
                            }
                        }
                    }
                }
            }

            ECReportGroup Group = new ECReportGroup();
            Result.AddGroup(Group);

            if (m_Spec.Output.IsIncludeCount)
            {
                ECReportGroupCount Count = new ECReportGroupCount(m_DefaultTagGroup.Count);
                Group.GroupCount = Count;
            }

            foreach (EPC Epc in m_DefaultTagGroup)
            {
                EPCWrapper Wrapper = Epc as EPCWrapper;
                ECReportGroupListMember Member = new ECReportGroupListMember();
                Group.AddMember(Member);
                Member.EpcTag = Wrapper;

                if (m_Spec.Output.IsIncldeEPC)
                {
                    Member.EpcSet = true;
                }
                if (m_Spec.Output.IsIncludeTag)
                {
                    Member.TagSet = true;
                }
                if (m_Spec.Output.IsIncludeRawDecimal)
                {
                    Member.RawDecSet = true;
                }
                if (m_Spec.Output.IsIncludeRawHex)
                {
                    Member.RawHexSet = true;
                }
            }

            return Result;
        }
    }
}
